package top.itbook.util;

import java.security.MessageDigest;
import java.security.Provider;

/**
 * 消息摘要算法安全 - 单向散列函数(Hash) - MD2算法
 * 本类采用懒汉单例模式 - 调用getInstance方法获取本类实例
 * 散列算法介绍（语文介绍水平不好，则直接复制百科内容）
 * 散列函数（或散列算法，又称哈希函数，英语：Hash Function）
 * 是一种从任何一种数据中创建小的数字“指纹”的方法。
 * 散列函数把消息或数据压缩成摘要，使得数据量变小，将数据的格式固定下来。
 * 该函数将数据打乱混合，重新创建一个叫做散列值（hash values，hash codes，hash sums，或hashes）的指纹。
 * 散列值通常用一个短的随机字母和数字组成的字符串来代表。
 * 算法重点：好的散列函数在输入域中很少出现散列冲突。
 * 在散列表和数据处理中，不抑制冲突来区别数据，会使得数据库记录更难找到。
 */
public class MD2 extends Provider {
    // 使用静态成员变量存储本类对象
    private static MD2 instance;

    private final static String salt = "@KingMD2.top"; // 盐值



    // 不使用static修饰符以防止没通过实例化对象调用方法

    // 私有化有参构造器 - 不建议使用暴力反射获取！
    private MD2(String name,String versionStr,String info){
        super(name,versionStr,info); // 调用父类构造器创建对象
    }

    /**
     * 返回本类实例化对象
     * @return MD2类实例化对象
     */
    public static MD2 getInstance(){
        if (instance == null){
            instance = new MD2("King","0.3","MD2信息摘要加密算法，此算法在原先基础上进行了加盐处理，这将会让通过彩虹表破解的方式变得极其困难");
        }
        return instance;
    }

    /**
     * MD2加密算法(加盐) - 不可逆加密 - 加密字符串
     * @param content 要加密的字符串
     * @return MD2算法加密后的密文 - 若返回null则可能出现无法预知的报错
     */
    public String md2encryptionPLUS(String content) {
        MessageDigest messageDigest;
        String s = null; // 加密后的十六进制字符串
        try {
            // 获取MessageDigest类的实例
            messageDigest = MessageDigest.getInstance("MD2");
            // 把用户输入的字符串与盐值进行拼接
            content = content + salt;
            // 更新摘要
            messageDigest.update(content.getBytes());
            // 获取数据的信息摘要 - 进行哈希计算
            byte[] resultBytes = messageDigest.digest();
            // 将信息摘要转换为十六进制字符串
            s = convertString(resultBytes);
        } catch (Exception exception) {
            // 打印异常栈信息
            exception.printStackTrace();
        }
        return s;
    }

    /**
     * MD2加密算法 - 不可逆加密 - 加密字符串 - 没有加盐的版本不推荐使用
     * @param content 要加密的字符串
     * @return MD2算法加密后的密文 - 若返回null则可能出现无法预知的报错
     */
    @Deprecated
    public String md2encryption(String content) {
        MessageDigest messageDigest;
        String s = null; // 加密后的十六进制字符串
        try {
            // 获取MessageDigest类的实例
            messageDigest = MessageDigest.getInstance("MD2");
            // 更新摘要
            messageDigest.update(content.getBytes());
            // 获取数据的信息摘要 - 进行哈希计算
            byte[] resultBytes = messageDigest.digest();
            // 将信息摘要转换为十六进制字符串
            s = convertString(resultBytes);
        } catch (Exception exception) {
            // 打印异常栈信息
            exception.printStackTrace();
        }
        return s;
    }

    /**
     * 将字节数组转换为十六进制字符串 - 仅为此类提供工具方法，切勿暴力反射获取，否则将对系统速度造成影响
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private String convertString(byte[] bytes){
        StringBuilder stringBuffer = new StringBuilder(bytes.length * 2);
        // 使用string的format方法进行转换
        for (byte aByte : bytes) {
            stringBuffer.append(String.format("%02x", aByte & 0xff));
        }
        return stringBuffer.toString();
    }
}
